package me.itsoo.artemis.framework.repository.config;

import lombok.Getter;
import me.itsoo.artemis.framework.core.ResourceScanner;
import me.itsoo.artemis.framework.core.util.CollectionUtils;
import me.itsoo.artemis.framework.repository.interceptor.SqlInterceptor;
import me.itsoo.artemis.framework.repository.mapper.SqlMapper;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

/**
 * ClassBindingRegistry
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/5/28
 */
public class ClassBindingRegistry {

    private static final Map<String, ClassBindingRegistry> LOADED_CBR_CACHE = new HashMap<>(32);

    @Getter
    private final String basePackage;

    private final Set<Class<?>> foundClasses;

    private ClassBindingRegistry(String basePackage) {
        this.basePackage = basePackage;
        this.foundClasses = new ResourceScanner(basePackage).getClasses();
    }

    /**
     * 获取 ClassBindingRegistry
     *
     * @param basePackage String
     * @return ClassBindingRegistry
     */
    public static synchronized ClassBindingRegistry get(String basePackage) {
        return LOADED_CBR_CACHE.computeIfAbsent(basePackage, ClassBindingRegistry::new);
    }

    /**
     * 获取全部扫描类
     *
     * @return Set
     */
    public Set<Class<?>> getClasses() {
        return new LinkedHashSet<>(foundClasses);
    }

    /**
     * 获取符合条件的扫描类
     *
     * @param predicate Predicate
     * @return Set
     */
    public Set<Class<?>> getClasses(Predicate<Class<?>> predicate) {
        return CollectionUtils.filter(new LinkedHashSet<>(foundClasses), predicate);
    }

    /**
     * 获取所有 SqlInterceptor
     *
     * @return Set
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public Set<Class<SqlInterceptor>> getSqlInterceptorClasses() {
        return (Set) getClasses(SqlInterceptor.class::isAssignableFrom);
    }

    /**
     * 获取所有 SqlMapper
     *
     * @return Set
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public Set<Class<SqlMapper>> getSqlMapperClasses() {
        return (Set) getClasses(SqlMapper.class::isAssignableFrom);
    }
}
